#ifndef H_6LOWPAN
#define H_6LOWPAN

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <stdint.h>

//devices of interest between which we have 
//adapt the traffic
#include <ieee802154.h>
#include <linux/if_tun.h>

#define VERSION 1.0

lowpan_device_t device;

int open_and_config_lowpan(lowpan_device_t * dev);
int open_and_config_tun(const lowpan_device_t const * dev);
int protocol_loop(int router_mode);

typedef struct lowpan_iphc lowpan_iphc_t;
typedef struct lowpan_udphc lowpan_udphc_t;
typedef struct lowpan_meshc lowpan_meshc_t;
typedef struct lowpan_fraghc lowpan_fraghc_t;
typedef struct lowpan_frag_ini lowpan_frag_ini_t;
typedef struct lowpan_frag_cont lowpan_frag_cont_t;
typedef struct ipv6_preffix_uncomp  ipv6_preffix_uncomp_t;
typedef struct next_header_uncomp  next_header_uncomp_t;

typedef struct lowpan_device lowpan_device_t;

struct lowpan_device {
	uint64_t preffix;
	union {
		uint64_t mac_addr_long;
		uint16_t mac_addr_short;
	};			
} __attribute__((__packed__));

struct lowpan_meshc {
	uint8_t type:2; //header type should be always 10
	uint8_t v_flag:1; //originator address type 0 if address is EUI-64 64 bits long or 1 if 16 bits short address
	uint8_t f_flag:1; //destination address type 0 if address is EUI-64 64 bits long or 1 if 16 bits short address
	uint8_t ttl:4; //hops left decremented at each hop, frame discarded if zero
	union {
		uint16_t src_short;
		uint64_t src_long;		
	};
	union {
		uint16_t dst_short;
		uint64_t dst_long;		
	};
} __attribute__((__packed__));

//fragmentation header compression
struct lowpan_fraghc {
	uint8_t type:2; //fragmentation header type should be always 11
	uint8_t frag:3; //encoding 000 initial frame; 100 continuous frame
} __attribute__((__packed__));

//intial fragment
struct lowpan_frag_ini {
	uint16_t size:11; //datagram size
	uint16_t tag; //fragment index
} __attribute__((__packed__));

//continuation fragment 
struct lowpan_frag_cont {
	uint16_t size:11; //datagram size
	uint16_t tag; //fragment index
	uint8_t offset; //fragment offset
} __attribute__((__packed__));

//IPv6 compressed header
struct lowpan_iphc {
	uint8_t saddr_flag:2; //source address type 00:  PI, II 01:  PI, IC 10:  PC, II 11:  PC, IC 
	uint8_t daddr_flag:2; //destination address type
	uint8_t class_flag:1; //traffic class and flow lable comressed (1) or carried in-lined (0)
	uint8_t nh_flag:2; //next header identification 00:  not compressed; full 8 bits are sent 01:  UDP 10:  ICMP 11:  TCP 
	uint8_t nexthc_flag:1; //0: No more header compression bits; 1: HC1 encoding immediately followed by more header compression
} __attribute__((__packed__));

//IPv6 preffix that can be included into the packet if IC or PC flags set in ipch header
struct ipv6_preffix_uncomp {
	uint64_t preffix;
} __attribute__((__packed__));

//IPv6 preffix that can be included into the packet if IC or PC flags set in ipch header
struct next_header_uncomp {
	uint8_t next_header;
} __attribute__((__packed__));

//udp compression header
struct lowpan_udphc {
	uint8_t hc2; //header compression encoding : bit 0 sport bit 1 dport bit 2 length bits 3-7 reserved and always 0s
	uint8_t sp:4; //source port
	uint8_t dp:4; //destination port
	uint16_t checksum; //UDP checksum
} __attribute__((__packed__));

#endif //H_6LOWPAN
